// Copyright (c) Lawrence Livermore National Security, LLC and other VisIt
// Project developers.  See the top-level LICENSE file for dates and other
// details.  No copyright assignment is required to contribute to VisIt.

#include <QvisContourPlotWindow.h>

#include <math.h>

#include <QButtonGroup>
#include <QCheckBox>
#include <QComboBox>
#include <QGroupBox>
#include <QLabel>
#include <QLayout>
#include <QLineEdit>
#include <QRadioButton>

#include <QvisColorButton.h>
#include <QvisColorManagerWidget.h>
#include <QvisColorTableWidget.h>
#include <QvisLineWidthWidget.h>
#include <QvisOpacitySlider.h>
#include <ContourAttributes.h>
#include <ViewerProxy.h>

#include <DebugStream.h>

// ****************************************************************************
// Method: QvisContourPlotWindow::QvisContourPlotWindow
//
// Purpose: 
//   Constructor for the QvisContourPlotWindow class.
//
// Programmer: Brad Whitlock
// Creation:   Sat Feb 17 13:42:22 PST 2001
//
// Modifications:
//   Eric Brugger, Wed Mar 14 12:00:23 PST 2001
//   I added the argument type.
//
//   Brad Whitlock, Tue Jul 15 15:17:01 PDT 2008
//   Qt 4.
//
// ****************************************************************************

QvisContourPlotWindow::QvisContourPlotWindow(const int type,
    ContourAttributes *contourAtts_, const QString &caption,
    const QString &shortName, QvisNotepadArea *notepad) :
    QvisPostableWindowObserver(contourAtts_, caption, shortName, notepad)
{
    plotType    = type;
    contourAtts = contourAtts_;
    colorModeButtons = 0;
    scalingButtons = 0;
}

// ****************************************************************************
// Method: QvisContourPlotWindow::~QvisContourPlotWindow
//
// Purpose: 
//   Destructor for the QvisContourPlotWindow class.
//
// Programmer: Brad Whitlock
// Creation:   Tue Aug 1 17:06:01 PST 2000
//
// Modifications:
//   Brad Whitlock, Tue Jul 15 15:16:52 PDT 2008
//   Qt 4.
//
// ****************************************************************************

QvisContourPlotWindow::~QvisContourPlotWindow()
{
    contourAtts = 0;
}

// ****************************************************************************
// Method: QvisContourPlotWindow::CreateWindowContents
//
// Purpose: 
//   This method creates the widgets that are in the window and sets
//   up their signals/slots.
//
// Notes:
//   The color selection portions of this window are not yet implemented.
//
// Programmer: Brad Whitlock
// Creation:   Sat Feb 17 13:42:22 PST 2001
//
// Modifications:
//   Kathleen Bonnell, Wed Feb 28 14:47:56 PST 2001
//   Added radio buttons for selecting scale.
//
//   Jeremy Meredith, Wed Mar 13 10:20:32 PST 2002
//   Added a toggle for wireframe mode.
//
//   Brad Whitlock, Thu Aug 22 10:26:08 PDT 2002
//   I added an opacity slider for single color opacity.
//
//   Brad Whitlock, Tue Dec 3 08:54:59 PDT 2002
//   I added a color table button.
//
//   Brad Whitlock, Mon Sep 8 17:02:29 PST 2003
//   I changed some menu labels to plural.
//
//   Brad Whitlock, Tue Apr 22 16:26:59 PDT 2008
//   Added tr()'s.
//
//   Brad Whitlock, Tue Jul 15 15:05:35 PDT 2008
//   Qt 4.
//
//   Dave Pugmire, Wed Oct 29 16:00:48 EDT 2008
//   Swap the min/max in the gui.
//
//   Allen Sanderson, Sun Mar  7 12:49:56 PST 2010
//   Change layout of window for 2.0 interface changes.
//
//   Kathleen Bonnell, Mon Jan 17 17:59:09 MST 2011
//   Change colorTableButton to colorTableWidget to gain invert toggle.
//
//   Kathleen Biagas, Tue Apr 18 16:34:41 PDT 2023
//   Support Qt6: buttonClicked -> idClicked.
//
// ****************************************************************************

void
QvisContourPlotWindow::CreateWindowContents()
{
    //
    // Create the scale group
    //
    QGroupBox * dataGroup = new QGroupBox(central);
    dataGroup->setTitle(tr("Contour Levels"));
    topLayout->addWidget(dataGroup);

    QGridLayout *dataLayout = new QGridLayout(dataGroup);
    dataLayout->setContentsMargins(5,5,5,5);
    dataLayout->setSpacing(10);

    //
    // Create the scale radio buttons
    //
    dataLayout->addWidget( new QLabel(tr("Scale"), central), 0, 0);
    
    // Create the radio buttons
    scalingButtons = new QButtonGroup(central);

    QRadioButton * rb = new QRadioButton(tr("Linear"), central);
    rb->setChecked(true);
    scalingButtons->addButton(rb, 0);
    dataLayout->addWidget(rb, 0, 1);
    rb = new QRadioButton(tr("Log"), central);
    scalingButtons->addButton(rb, 1);
    dataLayout->addWidget(rb, 0, 2);

    // Each time a radio button is clicked, call the scale clicked slot.
#if QT_VERSION < QT_VERSION_CHECK(6,0,0)
    connect(scalingButtons, SIGNAL(buttonClicked(int)),
            this, SLOT(scaleClicked(int)));
#else
    connect(scalingButtons, SIGNAL(idClicked(int)),
            this, SLOT(scaleClicked(int)));
#endif

    //
    // Create the Limits stuff
    //
    QGroupBox * limitsGroup = new QGroupBox(central);
    dataLayout->addWidget(limitsGroup, 1, 0, 1, 5);

    QGridLayout *limitsLayout = new QGridLayout(limitsGroup);
    limitsLayout->setContentsMargins(5,5,5,5);
    limitsLayout->setSpacing(10);

    // Create the min toggle and line edit
    minToggle = new QCheckBox(tr("Minimum"), central);
    limitsLayout->addWidget(minToggle, 0, 0);
    connect(minToggle, SIGNAL(toggled(bool)),
            this, SLOT(minToggled(bool)));
    minLineEdit = new QLineEdit(central);
    connect(minLineEdit, SIGNAL(returnPressed()),
            this, SLOT(processMinLimitText())); 
    limitsLayout->addWidget(minLineEdit, 0, 1);

    // Create the max toggle and line edit
    maxToggle = new QCheckBox(tr("Maximum"), central);
    limitsLayout->addWidget(maxToggle, 0, 2);
    connect(maxToggle, SIGNAL(toggled(bool)),
            this, SLOT(maxToggled(bool)));
    maxLineEdit = new QLineEdit(central);
    connect(maxLineEdit, SIGNAL(returnPressed()),
            this, SLOT(processMaxLimitText())); 
    limitsLayout->addWidget(maxLineEdit, 0, 3);



    // Add the select by combo box.
    selectByComboBox = new QComboBox(central);
    selectByComboBox->addItem(tr("N levels"));
    selectByComboBox->addItem(tr("Value(s)"));
    selectByComboBox->addItem(tr("Percent(s)"));
    connect(selectByComboBox, SIGNAL(activated(int)),
           this, SLOT(selectByChanged(int)));
    QLabel *selectByLabel = new QLabel(tr("Select by"), central);
    selectByLabel->setBuddy(selectByComboBox);
    dataLayout->addWidget(selectByLabel, 2, 0);
    dataLayout->addWidget(selectByComboBox, 2, 1);

    // Add the select by text field.
    selectByLineEdit = new QLineEdit(central);
    connect(selectByLineEdit, SIGNAL(returnPressed()),
           this, SLOT(processSelectByText()));
    dataLayout->addWidget(selectByLineEdit, 2, 2);

    // Create the contour color group box.
    contourColorGroup = new QGroupBox(central);
    contourColorGroup->setTitle(tr("Contour colors"));
    topLayout->addWidget(contourColorGroup);
    topLayout->setStretchFactor(contourColorGroup, 100);

    QGridLayout *colorLayout = new QGridLayout(contourColorGroup);
    colorLayout->setContentsMargins(5,5,5,5);
    colorLayout->setSpacing(10);

    // Create the mode buttons that determine if the window is in single,
    // multiple, or color table color mode.
    colorModeButtons = new QButtonGroup(contourColorGroup);
#if QT_VERSION < QT_VERSION_CHECK(6,0,0)
    connect(colorModeButtons, SIGNAL(buttonClicked(int)),
            this, SLOT(colorModeChanged(int)));
#else
    connect(colorModeButtons, SIGNAL(idClicked(int)),
            this, SLOT(colorModeChanged(int)));
#endif

    rb = new QRadioButton(tr("Color table"), contourColorGroup);
    colorModeButtons->addButton(rb, 0);
    colorLayout->addWidget(rb, 0, 0);
    rb = new QRadioButton(tr("Single"), contourColorGroup);
    colorModeButtons->addButton(rb, 1);
    colorLayout->addWidget(rb, 1, 0);
    rb = new QRadioButton(tr("Multiple"), contourColorGroup);
    colorModeButtons->addButton(rb, 2);
    colorLayout->addWidget(rb, 2, 0);

    // Create the single color button.
    singleColor = new QvisColorButton(contourColorGroup);
    singleColor->setButtonColor(QColor(255, 0, 0));
    connect(singleColor, SIGNAL(selectedColor(const QColor &)),
            this, SLOT(singleColorChanged(const QColor &)));
    colorLayout->addWidget(singleColor, 1, 1);
    // Create the single color opacity.
    singleColorOpacity = new QvisOpacitySlider(contourColorGroup);
    singleColorOpacity->setMinimum(0);
    singleColorOpacity->setMaximum(255);
    singleColorOpacity->setTickInterval(64);
    connect(singleColorOpacity, SIGNAL(valueChanged(int)),
            this, SLOT(singleColorOpacityChanged(int)));
    colorLayout->addWidget(singleColorOpacity, 1, 2);

    // Add the multiple colors widget.
    multipleColors = new QvisColorManagerWidget(contourColorGroup);
    multipleColors->setNameLabelText(tr("Level"));
    connect(multipleColors, SIGNAL(colorChanged(const QColor &, int)),
            this, SLOT(multipleColorChanged(const QColor &, int)));
    connect(multipleColors, SIGNAL(opacityChanged(int, int)),
            this, SLOT(opacityChanged(int, int)));
    colorLayout->addWidget(multipleColors, 3, 0, 1, 3);

    // Add the color table button.
    colorTableWidget = new QvisColorTableWidget(contourColorGroup, true);
    connect(colorTableWidget, SIGNAL(selectedColorTable(bool, const QString &)),
            this, SLOT(colorTableClicked(bool, const QString &)));
    connect(colorTableWidget,
            SIGNAL(invertColorTableToggled(bool)),
            this,
            SLOT(invertColorTableToggled(bool)));
    colorLayout->addWidget(colorTableWidget, 0, 1, 1, 2,
        Qt::AlignLeft | Qt::AlignVCenter);


    //
    // Create the style stuff
    //

    QGroupBox * styleGroup = new QGroupBox(central);
    styleGroup->setTitle(tr("Lines"));
    topLayout->addWidget(styleGroup);

    QGridLayout *styleLayout = new QGridLayout(styleGroup);
    styleLayout->setContentsMargins(5,5,5,5);
    styleLayout->setSpacing(10);
 
    // Create the lineWidth widget.
    styleLayout->addWidget(new QLabel(tr("Line width"), central), 1, 2);

    lineWidth = new QvisLineWidthWidget(0, central);
    connect(lineWidth, SIGNAL(lineWidthChanged(int)),
            this, SLOT(lineWidthChanged(int)));
    styleLayout->addWidget(lineWidth, 1, 3);

    //
    // Create the misc stuff
    //
    QGroupBox * miscGroup = new QGroupBox(central);
    miscGroup->setTitle(tr("Misc"));
    topLayout->addWidget(miscGroup);

    QGridLayout *miscLayout = new QGridLayout(miscGroup);
    miscLayout->setContentsMargins(5,5,5,5);
    miscLayout->setSpacing(10);
 
    // Create the legend toggle
    legendToggle = new QCheckBox(tr("Legend"), central);
    connect(legendToggle, SIGNAL(toggled(bool)),
            this, SLOT(legendToggled(bool)));
    miscLayout->addWidget(legendToggle, 0, 0);

    // Create the wireframe toggle
    wireframeToggle = new QCheckBox(tr("Wireframe"), central);
    connect(wireframeToggle, SIGNAL(toggled(bool)),
            this, SLOT(wireframeToggled(bool)));
    miscLayout->addWidget(wireframeToggle, 0, 1);
}

// ****************************************************************************
// Method: QvisContourPlotWindow::UpdateWindow
//
// Purpose: 
//   This method is called when the window's subject is changed. The
//   subject tells this window what attributes changed and we put the
//   new values into those widgets.
//
// Arguments:
//   doAll : If this flag is true, update all the widgets regardless
//           of whether or not they are selected.
//
// Returns:    
//
// Note:       
//
// Programmer: Brad Whitlock
// Creation:   Sat Feb 17 13:42:22 PST 2001
//
// Modifications:
//
//   Kathleen Bonnell, Mon Mar 26 18:17:53 PST 2001
//   Disabled lineStyle and lineStyleLabel until we have vtk version
//   in which line stippling is available.
//
//   Kathleen Bonnell, Thu Jun 21 16:33:54 PDT 2001
//   Enable lineStyle and lineStyleLabel. 
//
//   Jeremy Meredith, Wed Mar 13 10:20:32 PST 2002
//   Added a toggle for wireframe mode.
//
//   Brad Whitlock, Thu Aug 22 10:33:06 PDT 2002
//   I added code to update the single color opacity slider and set the 
//   enabled state for the single and multiple color widgets.
//
//   Kathleen Bonnell, Thu Oct  3 13:23:42 PDT 2002  
//   I added code to disable min/max if contourMethod is "value", ensure
//   it is enabled otherwise. 
//
//   Brad Whitlock, Fri Nov 22 12:07:38 PDT 2002
//   I added new attributes to support color tables.
//
//   Jeremy Meredith, Tue Nov 16 11:39:53 PST 2004
//   Replaced simple QString::sprintf's with a setNum because there seems
//   to be a bug causing numbers to be incremented by .00001.  See '5263.
//
//   Brad Whitlock, Tue Apr 22 16:27:30 PDT 2008
//   Added tr()'s
//
//   Brad Whitlock, Tue Jul 15 15:21:40 PDT 2008
//   Qt 4.
//
//   Kathleen Bonnell, Mon Jan 17 17:59:09 MST 2011
//   Change colorTableButton to colorTableWidget to gain invert toggle.
//
//   Kathleen Biagas, Wed Apr  8 08:42:11 PDT 2015
//   Use DoubleToQString helper function, for consistency in formatting across
//   all windows.
//
// ****************************************************************************

void
QvisContourPlotWindow::UpdateWindow(bool doAll)
{
    bool updateColors = false;
    bool updateNames = false;
    int  index;

    // Loop through all the attributes and do something for
    // each of them that changed. This function is only responsible
    // for displaying the state values and setting widget sensitivity.
    for(int i = 0; i < contourAtts->NumAttributes(); ++i)
    {
        if(!doAll)
        {
            if(!contourAtts->IsSelected(i))
            continue;
        }

        switch(i)
        {
        case ContourAttributes::ID_defaultPalette:
            // Do nothing
            break;
        case ContourAttributes::ID_changedColors:
            // Do nothing
            break;
        case ContourAttributes::ID_colorType:
            colorModeButtons->blockSignals(true);
            if(contourAtts->GetColorType() == ContourAttributes::ColorByColorTable) 
                index = 0;
            else if(contourAtts->GetColorType() == ContourAttributes::ColorBySingleColor) 
                index = 1;
            else
                index = 2;
            colorModeButtons->button(index)->setChecked(true);
            colorModeButtons->blockSignals(false);

            singleColor->setEnabled(index == 1);
            singleColorOpacity->setEnabled(index == 1);
            colorTableWidget->setEnabled(index == 0);
            break;
        case ContourAttributes::ID_colorTableName:
            colorTableWidget->setColorTable(contourAtts->GetColorTableName().c_str());
            break;
        case ContourAttributes::ID_invertColorTable:
            colorTableWidget->setInvertColorTable(contourAtts->GetInvertColorTable());
            break;
        case ContourAttributes::ID_legendFlag:
            legendToggle->blockSignals(true);
            legendToggle->setChecked(contourAtts->GetLegendFlag());
            legendToggle->blockSignals(false);
            break;
        case ContourAttributes::ID_lineWidth:
            lineWidth->blockSignals(true);
            lineWidth->SetLineWidth(contourAtts->GetLineWidth());
            lineWidth->blockSignals(false);
            break;
        case ContourAttributes::ID_singleColor:
            { // new scope
            QColor temp(contourAtts->GetSingleColor().Red(),
                        contourAtts->GetSingleColor().Green(),
                        contourAtts->GetSingleColor().Blue());
            singleColor->blockSignals(true);
            singleColor->setButtonColor(temp);
            singleColor->blockSignals(false);
            singleColorOpacity->blockSignals(true);
            singleColorOpacity->setValue(contourAtts->GetSingleColor().Alpha());
            singleColorOpacity->setGradientColor(temp);
            singleColorOpacity->blockSignals(false);
            }
            break;
        case ContourAttributes::ID_multiColor:
            updateColors = true;
            break;
        case ContourAttributes::ID_contourNLevels:
            updateNames = true;
            updateColors = true;

            if(contourAtts->GetContourMethod() == ContourAttributes::Level)
                UpdateSelectByText();
            break;
        case ContourAttributes::ID_contourValue:
            updateNames = true;
            updateColors = true;

            if(contourAtts->GetContourMethod() == ContourAttributes::Value)
                UpdateSelectByText();
            break;
        case ContourAttributes::ID_contourPercent:
            updateNames = true;
            updateColors = true;

            if(contourAtts->GetContourMethod() == ContourAttributes::Percent)
                UpdateSelectByText();
            break;
        case ContourAttributes::ID_contourMethod:
            selectByComboBox->blockSignals(true);
            selectByComboBox->setCurrentIndex(contourAtts->GetContourMethod());
            selectByComboBox->blockSignals(false);

            // Set the column header for the name on the color manager.
            if(contourAtts->GetContourMethod() == ContourAttributes::Level)
            {
                minToggle->setEnabled(true);
                minLineEdit->setEnabled(contourAtts->GetMinFlag());
                maxToggle->setEnabled(true);
                maxLineEdit->setEnabled(contourAtts->GetMaxFlag());
                multipleColors->setNameLabelText(tr("Level"));
            }

            else if(contourAtts->GetContourMethod() == ContourAttributes::Value)
            {
                minToggle->setEnabled(false);
                minLineEdit->setEnabled(false);
                maxToggle->setEnabled(false);
                maxLineEdit->setEnabled(false);
                multipleColors->setNameLabelText(tr("Value"));
            }
            else if(contourAtts->GetContourMethod() == ContourAttributes::Percent)
            {
                minToggle->setEnabled(true);
                minLineEdit->setEnabled(contourAtts->GetMinFlag());
                maxToggle->setEnabled(true);
                maxLineEdit->setEnabled(contourAtts->GetMaxFlag());
                multipleColors->setNameLabelText(tr("Percent"));
            }

            updateNames = true;
            updateColors = true;
            UpdateSelectByText();
            break;
        case ContourAttributes::ID_minFlag:
            minToggle->blockSignals(true);
            minToggle->setChecked(contourAtts->GetMinFlag());
            minLineEdit->setEnabled(contourAtts->GetMinFlag());
            minToggle->blockSignals(false);
            break;
        case ContourAttributes::ID_maxFlag:
            maxToggle->blockSignals(true);
            maxToggle->setChecked(contourAtts->GetMaxFlag());
            maxLineEdit->setEnabled(contourAtts->GetMaxFlag());
            maxToggle->blockSignals(false);
            break;
        case ContourAttributes::ID_min:
            minLineEdit->setText(DoubleToQString(contourAtts->GetMin()));
            break;
        case ContourAttributes::ID_max:
            maxLineEdit->setText(DoubleToQString(contourAtts->GetMax()));
            break;
        case ContourAttributes::ID_scaling:
            scalingButtons->button(contourAtts->GetScaling())->setChecked(true);
            break;
        case ContourAttributes::ID_wireframe:
            wireframeToggle->blockSignals(true);
            wireframeToggle->setChecked(contourAtts->GetWireframe());
            wireframeToggle->blockSignals(false);
            break;
        }
    } // end for

    // If we need to update the colors, update them now. This ensures that it
    // is only done one time no matter what combination of attributes was
    // selected.
    bool multiEnabled = (contourAtts->GetColorType() ==
        ContourAttributes::ColorByMultipleColors);
    if(updateColors)
        multiEnabled &= UpdateMultipleAreaColors();

    // If we need to update the names, update them now.
    if(updateNames)
        multiEnabled &= UpdateMultipleAreaNames();

    // Set the enabled state for the multiple color widget.
    multipleColors->setEnabled(multiEnabled);
}

// ****************************************************************************
// Method: QvisContourPlotWindow::UpdateMultipleAreaColors
//
// Purpose: 
//   This method updates the multipleColors widget with the list of contour
//   colors.
//
// Programmer: Brad Whitlock
// Creation:   Sat Feb 17 13:42:22 PST 2001
//
// Modifications:
//   Brad Whitlock, Thu Aug 22 12:31:19 PDT 2002
//   I made it return true if the widget should be enabled.
//
// ****************************************************************************

bool
QvisContourPlotWindow::UpdateMultipleAreaColors()
{
    const ColorAttributeList &contourColors = contourAtts->GetMultiColor();
    int   i, nEntries;
    int   cm = contourAtts->GetContourMethod();

    if(cm == ContourAttributes::Level)
        nEntries = contourAtts->GetContourNLevels();
    else if(cm == ContourAttributes::Value)
        nEntries = (int)contourAtts->GetContourValue().size();
    else
        nEntries = (int)contourAtts->GetContourPercent().size();

    // Block the signals from the multipleColors widget.
    multipleColors->blockSignals(true);

    if(nEntries == multipleColors->numEntries())
    {
        for(i = 0; i < nEntries; ++i)
        {
            QColor temp(contourColors[i].Red(), contourColors[i].Green(),
                        contourColors[i].Blue());

            multipleColors->setColor(i, temp);
            multipleColors->setOpacity(i, contourColors[i].Alpha());
        }
    }
    else if(nEntries > multipleColors->numEntries())
    {
        // Set all of the existing colors.
        for(i = 0; i < multipleColors->numEntries(); ++i)
        {
            QColor temp(contourColors[i].Red(), contourColors[i].Green(),
                        contourColors[i].Blue());

            multipleColors->setColor(i, temp);
            multipleColors->setOpacity(i, contourColors[i].Alpha());
        }

        // Add new entries
        for(i = multipleColors->numEntries();
            i < nEntries; ++i)
        {
            QColor temp(contourColors[i].Red(), contourColors[i].Green(),
                        contourColors[i].Blue());

            multipleColors->addEntry(QString(""), temp, contourColors[i].Alpha());
        }
    }
    else // nEntries < multipleColors->numEntries()
    {
        // Set all of the existing names.
        for(i = 0; i < nEntries; ++i)
        {
            QColor temp(contourColors[i].Red(), contourColors[i].Green(),
                        contourColors[i].Blue());

            multipleColors->setColor(i, temp);
            multipleColors->setOpacity(i, contourColors[i].Alpha());
        }

        // Remove excess entries
        int numEntries = multipleColors->numEntries();
        for(i = nEntries;
            i < numEntries; ++i)
        {
            multipleColors->removeLastEntry();
        }
    }

    // Unblock the signals from the multipleColors widget.
    multipleColors->blockSignals(false);

    return (nEntries > 0);
}

// ****************************************************************************
// Method: QvisContourPlotWindow::LevelString
//
// Purpose: 
//   Returns a string version of the data value that we want.
//
// Arguments:
//   i : The index of the data value that we want to use.
//
// Returns:    A string version of the data value that we want.
//
// Programmer: Brad Whitlock
// Creation:   Fri Feb 16 14:18:36 PST 2001
//
// Modifications:
//   Jeremy Meredith, Tue Nov 16 11:39:53 PST 2004
//   Replaced simple QString::sprintf's with a setNum because there seems
//   to be a bug causing numbers to be incremented by .00001.  See '5263.
//
//   Kathleen Biagas, Thu Apr 9 07:19:54 MST 2015
//   Use helper function DoubleToQString for consistency in formatting across
//   all windows.
//
// ****************************************************************************

QString
QvisContourPlotWindow::LevelString(int i)
{
    QString retval("");
    int     cm = contourAtts->GetContourMethod();

    if(cm == ContourAttributes::Level)
        retval  = IntToQString(i+1);
    else if(cm == ContourAttributes::Value)
        retval = DoubleToQString(contourAtts->GetContourValue()[i]);
    else
    {
        retval = DoubleToQString(contourAtts->GetContourPercent()[i]);
        retval += "%";
    }

    return retval;
}

// ****************************************************************************
// Method: QvisContourPlotWindow::UpdateMultipleAreaNames
//
// Purpose: 
//   This method updates the multipleColors widget with the list of contour
//   names.
//
// Programmer: Brad Whitlock
// Creation:   Sat Feb 17 13:42:22 PST 2001
//
// Modifications:
//   Brad Whitlock, Thu Aug 22 12:31:51 PDT 2002
//   I made it return true if the widget should be enabled.
//
// ****************************************************************************

bool
QvisContourPlotWindow::UpdateMultipleAreaNames()
{
    QString temp;
    int     i, vecSize;
    int     cm = contourAtts->GetContourMethod();

    if(cm == ContourAttributes::Level)
        vecSize = contourAtts->GetContourNLevels();
    else if(cm == ContourAttributes::Value)
        vecSize = (int)contourAtts->GetContourValue().size();
    else
        vecSize = (int)contourAtts->GetContourPercent().size();

    if(vecSize == multipleColors->numEntries())
    {
        for(i = 0; i < vecSize; ++i)
        {
            temp = LevelString(i);
            multipleColors->setAttributeName(i, temp);
        }
    }
    else if(vecSize > multipleColors->numEntries())
    {
        // Set all of the existing names.
        for(i = 0; i < multipleColors->numEntries(); ++i)
        {
            temp = LevelString(i);
            multipleColors->setAttributeName(i, temp);
        }

        // Add new entries
        for(i = multipleColors->numEntries(); i < vecSize; ++i)
        {
            temp = LevelString(i);
            multipleColors->addEntry(temp, QColor(0,0,0), 255);
        }
    }
    else // if(vecSize < multipleColors->numEntries())
    {
        // Set all of the existing names.
        for(i = 0; i < vecSize; ++i)
        {
            temp = LevelString(i);
            multipleColors->setAttributeName(i, temp);
        }

        // Remove excess entries
        int numEntries = multipleColors->numEntries();
        for(i = vecSize; i < numEntries; ++i)
        {
            multipleColors->removeLastEntry();
        }
    }

    return (vecSize > 0);
}

// ****************************************************************************
// Method: QvisContourPlotWindow::UpdateSelectByText
//
// Purpose: 
//   This method updates the selectBy line edit when the value, percent, or
//   NLevels change.
//
// Programmer: Brad Whitlock
// Creation:   Sat Feb 17 12:18:33 PDT 2001
//
// Modifications:
//   Kathleen Biagas, Thu Apr 9 07:19:54 MST 2015
//   Use helper function DoubleToQString for consistency in formatting across
//   all windows.
//
// ****************************************************************************

void
QvisContourPlotWindow::UpdateSelectByText()
{
    QString temp, temp2(" ");
    size_t     i;

    if(contourAtts->GetContourMethod() == ContourAttributes::Level)
    {
        selectByLineEdit->setText(IntToQString(contourAtts->GetContourNLevels()));
    }
    else if(contourAtts->GetContourMethod() == ContourAttributes::Value)
    {
        for(i = 0; i < contourAtts->GetContourValue().size(); ++i)
        {
            temp += DoubleToQString(contourAtts->GetContourValue()[i]);
            temp += temp2;
        }
        selectByLineEdit->setText(temp);
    }
    else if(contourAtts->GetContourMethod() == ContourAttributes::Percent)
    {
        for(i = 0; i < contourAtts->GetContourPercent().size(); ++i)
        {
            temp += DoubleToQString(contourAtts->GetContourPercent()[i]);
            temp += temp2;
        }
        selectByLineEdit->setText(temp);
    }
}

// ****************************************************************************
// Method: QvisContourPlotWindow::GetCurrentValues
//
// Purpose: 
//   Gets the current values from the text fields and puts the values in the
//   contourAtts.
//
// Arguments:
//   which_widget : A number indicating which line edit for which to get
//                  the value. An index of -1 gets them all.
//
// Programmer: Brad Whitlock
// Creation:   Sat Feb 17 09:59:39 PDT 2001
//
// Modifications:
//   Brad Whitlock, Tue Apr 22 16:29:24 PDT 2008
//   Support for internationalization.
//
//   Brad Whitlock, Tue Jul 15 16:40:16 PDT 2008
//   Qt 4.
//
// ****************************************************************************

void
QvisContourPlotWindow::GetCurrentValues(int which_widget)
{
    bool doAll = (which_widget == -1);
    QString msg, temp;

    // Do the select by line edit.
    if(which_widget == 0 || doAll)
        ProcessSelectByText();

    // Do the minimum value.
    if(which_widget == ContourAttributes::ID_min || doAll)
    {
        double val;
        if(LineEditGetDouble(minLineEdit, val))
            contourAtts->SetMin(val);
        else
        {
            ResettingError(tr("minimum value"),
                         DoubleToQString(contourAtts->GetMin()));
            contourAtts->SetMin(contourAtts->GetMin());
        }
    }

    // Do the maximum value
    if(which_widget == ContourAttributes::ID_max || doAll)
    {
        double val;
        if(LineEditGetDouble(maxLineEdit, val))
            contourAtts->SetMax(val);
        else
        {
            ResettingError(tr("maximum value"),
                         DoubleToQString(contourAtts->GetMax()));
            contourAtts->SetMax(contourAtts->GetMax());
        }
    }
}

// ****************************************************************************
// Method: QvisContourPlotWindow::ProcessSelectByText
//
// Purpose: 
//   Processes the string in the selectByLineEdit and sets the results into
//   the contour attributes.
//
// Programmer: Brad Whitlock
// Creation:   Sat Feb 17 12:50:35 PDT 2001
//
// Modifications:
//   Brad Whitlock, Thu Feb 14 15:20:33 PST 2002
//   Added a code to prevent more than MAX_CONTOURS contours.
//
//   Mark C. Miller, Wed Nov 16 10:46:36 PST 2005
//   Added MAX_CONTOURS args to calls to StringToDoubleList 
//
//   Brad Whitlock, Tue Apr 22 16:30:36 PDT 2008
//   Support for internationalization.
//
//   Brad Whitlock, Tue Jul 15 15:39:11 PDT 2008
//   Qt 4.
//
// ****************************************************************************

void
QvisContourPlotWindow::ProcessSelectByText()
{
    doubleVector temp;

    if(contourAtts->GetContourMethod() == ContourAttributes::Level)
    {
        // Try converting the line edit to a double vector so we can take
        // the first element as the number of levels.
        int nlevels = contourAtts->GetContourNLevels();
        LineEditGetInt(selectByLineEdit, nlevels);

        // Prevent less than one contour
        if(nlevels < 1)
        {
            Warning(tr("VisIt requires at least one contour."));
            nlevels = 1;
        }

        // Prevent an excess number of contours.
        if(nlevels > ContourAttributes::MAX_CONTOURS)
        {
            QString tmp;
            tmp = tr("VisIt will not allow more than %1 contours.").
                  arg(ContourAttributes::MAX_CONTOURS);
            Warning(tmp);
            nlevels = ContourAttributes::MAX_CONTOURS;
        }

        contourAtts->SetContourNLevels(nlevels);
    }
    else if(contourAtts->GetContourMethod() == ContourAttributes::Value)
    {
        // Convert the text fo a list of doubles and store them in the
        // contour's value vector.
        LineEditGetDoubles(selectByLineEdit, temp,
                           ContourAttributes::MAX_CONTOURS);
        contourAtts->SetContourValue(temp);
    }
    else if(contourAtts->GetContourMethod() == ContourAttributes::Percent)
    {
        // Convert the text to a list of doubles and store them in the
        // contour's percent vector.
        LineEditGetDoubles(selectByLineEdit, temp,
                           ContourAttributes::MAX_CONTOURS);
        contourAtts->SetContourPercent(temp);
    }
}

// ****************************************************************************
// Method: QvisContourPlotWindow::Apply
//
// Purpose: 
//   This method applies the contour plot attributes and optionally
//   tells the viewer to apply them.
//
// Arguments:
//   ignore : This flag, when true, tells the code to ignore the
//            AutoUpdate function and tell the viewer to apply the
//            contour plot attributes.
//
// Programmer: Brad Whitlock
// Creation:   Sat Feb 17 13:42:22 PST 2001
//
// Modifications:
//   Kathleen Bonnell, Wed Feb 28 14:47:56 PST 2001
//   Added range checking for log plots.
//
//   Eric Brugger, Wed Mar 14 12:00:23 PST 2001
//   I modified the routine to pass to the viewer proxy the plot
//   type stored within the class instead of the one hardwired from
//   an include file.
//   
//   Kathleen Bonnell, Tue Mar 27 15:27:50 PST 2001
//   Removed range checking for log plots, as varMin, varMax no longer
//   members of ContourAttributes.  Range checking will now be done
//   within the plot itself and an exception thrown if invalid.
//
// ****************************************************************************

void
QvisContourPlotWindow::Apply(bool ignore)
{
    if(AutoUpdate() || ignore)
    {
        // Get the current contour plot attributes and tell the other
        // observers about them.
        GetCurrentValues(-1);
        contourAtts->Notify();

        // Tell the viewer to set the contour plot attributes.
        GetViewerMethods()->SetPlotOptions(plotType);
    }
    else
        contourAtts->Notify();
}

//
// Qt Slot functions...
//

// ****************************************************************************
// Method: QvisContourPlotWindow::apply
//
// Purpose: 
//   This is a Qt slot function that is called when the window's Apply
//   button is clicked.
//
// Programmer: Brad Whitlock
// Creation:   Sat Feb 17 13:42:22 PST 2001
//
// Modifications:
//   
// ****************************************************************************

void
QvisContourPlotWindow::apply()
{
    Apply(true);
}

// ****************************************************************************
// Method: QvisContourPlotWindow::makeDefault
//
// Purpose: 
//   This is a Qt slot function that is called when the window's
//   "Make default" button is clicked.
//
// Programmer: Brad Whitlock
// Creation:   Sat Feb 17 13:42:22 PST 2001
//
// Modifications:
//   Eric Brugger, Wed Mar 14 12:00:23 PST 2001
//   I modified the routine to pass to the viewer proxy the plot
//   type stored within the class instead of the one hardwired from
//   an include file.
//   
// ****************************************************************************

void
QvisContourPlotWindow::makeDefault()
{
    // Tell the viewer to set the default contour plot attributes.
    GetCurrentValues(-1);
    contourAtts->Notify();
    GetViewerMethods()->SetDefaultPlotOptions(plotType);
}

// ****************************************************************************
// Method: QvisContourPlotWindow::reset
//
// Purpose: 
//   This is a Qt slot function that is called when the window's
//   Reset button is clicked.
//
// Programmer: Brad Whitlock
// Creation:   Sat Feb 17 13:42:22 PST 2001
//
// Modifications:
//   
// ****************************************************************************

void
QvisContourPlotWindow::reset()
{
    // Tell the viewer to reset the contour plot attributes to the last
    // applied values.
    GetViewerMethods()->ResetPlotOptions(plotType);
}


// ****************************************************************************
// Method: QvisContourPlotWindow::lineWidthChanged
//
// Purpose: 
//   This is a Qt slot function that is called when the window's
//   line width widget is changed.
//
// Arguments:
//   newWidth : The new line width.
//
// Programmer: Brad Whitlock
// Creation:   Sat Feb 17 13:42:22 PST 2001
//
// Modifications:
//   
// ****************************************************************************

void
QvisContourPlotWindow::lineWidthChanged(int newWidth)
{
    contourAtts->SetLineWidth(newWidth);
    Apply();
}

// ****************************************************************************
// Method: QvisContourPlotWindow::legendToggled
//
// Purpose: 
//   This is a Qt slot function that is called when the window's
//   legend toggle button is clicked.
//
// Arguments:
//   val : The new toggle value.
//
// Programmer: Brad Whitlock
// Creation:   Sat Feb 17 13:42:22 PST 2001
//
// Modifications:
//   
// ****************************************************************************

void
QvisContourPlotWindow::legendToggled(bool val)
{
    contourAtts->SetLegendFlag(val);
    Apply();
}

// ****************************************************************************
// Method: QvisContourPlotWindow::wireframeToggled
//
// Purpose: 
//   This is a Qt slot function that is called when the window's
//   wireframe toggle button is clicked.
//
// Arguments:
//   val : The new toggle value.
//
// Programmer: Jeremy Meredith
// Creation:   March 13, 2002
//
// Modifications:
//   
// ****************************************************************************

void
QvisContourPlotWindow::wireframeToggled(bool val)
{
    contourAtts->SetWireframe(val);
    Apply();
}

// ****************************************************************************
// Method: QvisContourPlotWindow::colorModeChanged
//
// Purpose: 
//   This is a Qt slot function that is called when the single/multiple color
//   radio buttons are clicked.
//
// Arguments:
//   index : The index of the button that called this method. If index is 0
//           then the single color button was clicked, otherwise the multiple
//           colors button was clicked.
//
// Programmer: Brad Whitlock
// Creation:   Sat Feb 17 13:42:22 PST 2001
//
// Modifications:
//   Brad Whitlock, Tue Dec 3 09:28:36 PDT 2002
//   I rewrote the method.
//
// ****************************************************************************

void
QvisContourPlotWindow::colorModeChanged(int index)
{
    if(index == 0)
        contourAtts->SetColorType(ContourAttributes::ColorByColorTable);
    else if(index == 1)
        contourAtts->SetColorType(ContourAttributes::ColorBySingleColor);
    else
        contourAtts->SetColorType(ContourAttributes::ColorByMultipleColors);
    Apply();
}

// ****************************************************************************
// Method: QvisContourPlotWindow::singleColorChanged
//
// Purpose: 
//   This is a Qt slot function that is called when the single color button's
//   color changes.
//
// Arguments:
//   color : The new single color.
//
// Programmer: Brad Whitlock
// Creation:   Sat Feb 17 13:42:22 PST 2001
//
// Modifications:
//   Brad Whitlock, Thu Aug 22 10:44:37 PDT 2002
//   I added a little code to preserve the alpha component of the color.
//
// ****************************************************************************

void
QvisContourPlotWindow::singleColorChanged(const QColor &color)
{
    int alpha = contourAtts->GetSingleColor().Alpha();
    ColorAttribute temp(color.red(), color.green(), color.blue(), alpha);
    contourAtts->SetSingleColor(temp);
    Apply();
}

// ****************************************************************************
// Method: QvisContourPlotWindow::singleColorOpacityChanged
//
// Purpose: 
//   This is a Qt slot function that sets the opacity component of the
//   single color.
//
// Arguments:
//   opacity : The new opacity value.
//
// Programmer: Brad Whitlock
// Creation:   Thu Aug 22 10:46:22 PDT 2002
//
// Modifications:
//   
// ****************************************************************************

void
QvisContourPlotWindow::singleColorOpacityChanged(int opacity)
{
    contourAtts->GetSingleColor().SetAlpha(opacity);
    contourAtts->SelectSingleColor();
    Apply();
}

// ****************************************************************************
// Method: QvisContourPlotWindow::multipleColorChanged
//
// Purpose: 
//   This is a Qt slot function that is called when a new color is selected
//   for one of the color buttons in the multiple colors area.
//
// Arguments:
//   color : The new color for the button.
//   index : The index of the color that changed.
// 
// Programmer: Brad Whitlock
// Creation:   Sat Feb 17 13:42:22 PST 2001
//
// Modifications:
//   Brad Whitlock, Fri Mar 30 19:18:25 PST 2001
//   Made it conform to ContourAttribute's new interface.
//
//   Brad Whitlock, Mon Dec 9 11:01:45 PDT 2002
//   Added code to mark the color as having been changed.
//
// ****************************************************************************

void
QvisContourPlotWindow::multipleColorChanged(const QColor &color, int index)
{
    if(index >= 0 &&
       index < contourAtts->GetMultiColor().GetNumColors())
    {
        contourAtts->GetMultiColor()[index].SetRgb(color.red(), color.green(),
                                                   color.blue());
        contourAtts->SelectMultiColor();
        contourAtts->MarkColorAsChanged(index);

        Apply();
    }
}

// ****************************************************************************
// Method: QvisContourPlotWindow::opacityChanged
//
// Purpose: 
//   This is a Qt slot function that is called when the opacity changes for one
//   of the contours in the multiple colors area.
//
// Arguments:
//   opacity : The new opacity.
//   index   : The index of the contour that changed.
//
// Programmer: Brad Whitlock
// Creation:   Sat Feb 17 13:42:22 PST 2001
//
// Modifications:
//   Brad Whitlock, Fri Mar 30 19:18:25 PST 2001
//   Made it conform to ContourAttribute's new interface.
//
//   Brad Whitlock, Mon Dec 9 11:01:45 PDT 2002
//   Added code to mark the color as having been changed.
//
// ****************************************************************************

void
QvisContourPlotWindow::opacityChanged(int opacity, int index)
{
    if(index >= 0 &&
       index < contourAtts->GetMultiColor().GetNumColors())
    {
        contourAtts->GetMultiColor()[index].SetAlpha(opacity);
        contourAtts->SelectMultiColor();
        contourAtts->MarkColorAsChanged(index);

        Apply();
    }
}

// ****************************************************************************
// Method: QvisContourPlotWindow::selectByChanged
//
// Purpose: 
//   This is a Qt slot function that is called when the contour method changes.
//
// Arguments:
//   mode : The new contour method.
//
// Programmer: Brad Whitlock
// Creation:   Sat Feb 17 10:03:29 PDT 2001
//
// Modifications:
//   Brad Whitlock, Fri Nov 22 14:29:15 PST 2002
//   I made it work with the new attributes.
//
//   Brad Whitlock, Mon Dec 9 14:57:25 PST 2002
//   I fixed a bug that prevented the window from working correctly while
//   autoupdate is on.
//
// ****************************************************************************

void
QvisContourPlotWindow::selectByChanged(int mode)
{
    contourAtts->SetContourMethod(ContourAttributes::Select_by(mode));
    if(AutoUpdate())
        UpdateSelectByText();
    Apply();
}

// ****************************************************************************
// Method: QvisContourPlotWindow::processSelectByText
//
// Purpose: 
//   This is a Qt slot function that is called then the selectbyLineEdit
//   changes values.
//
// Programmer: Brad Whitlock
// Creation:   Sat Feb 17 10:04:18 PDT 2001
//
// Modifications:
//   
// ****************************************************************************

void
QvisContourPlotWindow::processSelectByText()
{
    GetCurrentValues(0);
    Apply();
}

// ****************************************************************************
// Method: QvisContourPlotWindow::minToggled
//
// Purpose: 
//   This is a Qt slot function that is called when the min toggle is clicked.
//
// Arguments:
//   val : The toggle's new value.
//
// Programmer: Brad Whitlock
// Creation:   Sat Feb 17 10:05:28 PDT 2001
//
// Modifications:
//   
// ****************************************************************************

void
QvisContourPlotWindow::minToggled(bool val)
{
    contourAtts->SetMinFlag(val);
    Apply();
}

// ****************************************************************************
// Method: QvisContourPlotWindow::scaleClicked
//
// Purpose: 
//   This is a Qt slot function that is called when a scale button is clicked. 
//
// Arguments:
//   button  :  Which scaling button was selected. 
//
// Programmer: Kathleen Bonnell 
// Creation:   February 27, 2001 
//
// Modifications:
//   Brad Whitlock, Fri Nov 22 14:28:55 PST 2002
//   Made it work with the new attributes.
//
// ****************************************************************************

void
QvisContourPlotWindow::scaleClicked(int button)
{
    // Only do it if it changed.
    ContourAttributes::Scaling val = ContourAttributes::Scaling(button);
    if (val != contourAtts->GetScaling())
    {
        contourAtts->SetScaling(val);
        Apply();
    }
}

// ****************************************************************************
// Method: QvisContourPlotWindow::processMinLimitText
//
// Purpose: 
//   This is a Qt slot function that is called when the min limit changes.
//
// Programmer: Brad Whitlock
// Creation:   Sat Feb 17 10:11:38 PDT 2001
//
// Modifications:
//   Brad Whitlock, Tue Jul 15 16:44:34 PDT 2008
//   updated style.
//
// ****************************************************************************

void
QvisContourPlotWindow::processMinLimitText()
{
    GetCurrentValues(ContourAttributes::ID_min);
    Apply();
}

// ****************************************************************************
// Method: QvisContourPlotWindow::maxToggled
//
// Purpose: 
//   This is a Qt slot function that is called when the max toggle is clicked.
//
// Arguments:
//   val : The toggle's new value.
//
// Programmer: Brad Whitlock
// Creation:   Sat Feb 17 10:05:28 PDT 2001
//
// Modifications:
//   
// ****************************************************************************

void
QvisContourPlotWindow::maxToggled(bool val)
{
    contourAtts->SetMaxFlag(val);
    Apply();
}

// ****************************************************************************
// Method: QvisContourPlotWindow::processMaxLimitText
//
// Purpose: 
//   This is a Qt slot function that is called when the max limit changes.
//
// Programmer: Brad Whitlock
// Creation:   Sat Feb 17 10:11:38 PDT 2001
//
// Modifications:
//   Brad Whitlock, Tue Jul 15 16:44:42 PDT 2008
//   updated style.
//
// ****************************************************************************

void
QvisContourPlotWindow::processMaxLimitText()
{
    GetCurrentValues(ContourAttributes::ID_max);
    Apply();
}

// ****************************************************************************
// Method: QvisContourPlotWindow::colorTableClicked
//
// Purpose: 
//   This is a Qt slot function that sets the desired color table into the
//   contour plot attributes.
//
// Arguments:
//   useDefault : Whether or not to use the default color table.
//   ctName     : The name of the color table to use.
//
// Programmer: Brad Whitlock
// Creation:   Mon Nov 25 17:53:36 PST 2002
//
// Modifications:
//   
// ****************************************************************************

void
QvisContourPlotWindow::colorTableClicked(bool, const QString &ctName)
{
    contourAtts->SetColorTableName(ctName.toStdString());
    Apply();
}

// ****************************************************************************
// Method: QvisContourPlotWindow::invertColorTableToggled
//
// Purpose: 
//   This is a Qt slot function that sets the invert color table flag into the
//   contour plot attributes.
//
// Arguments:
//   val    :  Whether or not to invert the color table.
//
// Programmer: Kathleen Bonnell
// Creation:   January  17, 2011
//
// Modifications:
//   
// ****************************************************************************

void
QvisContourPlotWindow::invertColorTableToggled(bool val)
{
    contourAtts->SetInvertColorTable(val);
    Apply();
}
